﻿using System.Linq.Expressions;
using MySql.Simple.Mapper.Finders;

namespace MySql.Simple.Mapper.Linq.Query
{
    /// <summary>
    /// Generates a MySQL SQL statement from an <see cref="Expression"/>.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class SqlGenerator<T> : ExpressionVisitor
    {
        private string sql = string.Empty;

        /// <summary>
        /// Generates the SQL.
        /// </summary>
        /// <param name="expression">The expression.</param>
        /// <returns></returns>
        public string GenerateSql(Expression expression)
        {
            // Parse the expression
            Visit(expression);

            //var tableName = TableNameFinder.Find(typeof(T));

            //sql = string.Format("SELECT * FROM `{0}` WHERE ", tableName) + sql + ";";

            return sql;
        }

        protected override Expression VisitMethodCall(MethodCallExpression expression)
        {
            if (!string.IsNullOrEmpty(sql)) sql += " ";

            sql += expression.Method.Name.ToUpper();

            if (expression.Method.Name == "Select")
            {
                foreach (var i in expression.Arguments)
                {
                    if (i is UnaryExpression)
                    {
                        var ue = (UnaryExpression) i;

                        if (ue.Operand is LambdaExpression)
                        {
                            var le = (LambdaExpression) ue.Operand;

                            if (le.Body is MemberExpression)
                            {
                                var me = (MemberExpression) le.Body;

                                sql += " `" + me.Member.Name + "`";
                            }
                        }
                    }

                    if (i is MethodCallExpression)
                    {
                        var mce = (MethodCallExpression) i;

                        sql += mce.Method.Name.ToUpper();

                        foreach (var arg in mce.Arguments)
                        {
                            if (arg is ConstantExpression)
                            {
                                var c = (ConstantExpression) arg;

                                sql += c.Value;
                            }
                        }
                    }
                }
            }

            return base.VisitMethodCall(expression);
        }

        protected override Expression VisitConditional(ConditionalExpression c)
        {
            sql += " " + c.Test.ToString().ToUpper();

            return base.VisitConditional(c);
        }

        protected override Expression VisitMemberAccess(MemberExpression m)
        {
            sql += " `" + m.Member.Name.ToLower() + "`";

            return base.VisitMemberAccess(m);
        }

        protected override Expression VisitConstant(ConstantExpression c)
        {
            sql += @" """ + c.Value + @"""";

            return base.VisitConstant(c);
        }

        protected override Expression VisitBinary(BinaryExpression be)
        {
            if (be.NodeType == ExpressionType.Equal)
            {
                var name = string.Empty;

                if (be.Left is MemberExpression)
                {
                    var me = (MemberExpression)be.Left;

                    name = me.Member.Name;
                }


                //sql += " `" + name + "` = " + be.Right;

                /*                if (ExpressionTreeHelpers.IsMemberEqualsValueExpression(be, typeof(T), "Title"))
                                {
                                    locations.Add(ExpressionTreeHelpers.GetValueFromEqualsExpression(be, typeof(T), "Title"));
                                    return be;
                                }
                                else if (ExpressionTreeHelpers.IsMemberEqualsValueExpression(be, typeof(T), "State"))
                                {
                                    locations.Add(ExpressionTreeHelpers.GetValueFromEqualsExpression(be, typeof(T), "State"));
                                    return be;
                                }
                                else*/

            }
            sql += " " + be.NodeType;


            return base.VisitBinary(be);
        }
    }
}